package com.itrip.log.module.web;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Controller;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itrip.log.core.ContextUtil;
import com.itrip.log.module.db.IDao;

@Controller
@RequestMapping("/base")
public class BaseService implements ApplicationListener<ContextRefreshedEvent> {

	@Autowired
	@Qualifier("daoTemplate")
	private IDao daoTemplate;

	private Logger log = LoggerFactory.getLogger(BaseService.class);

	private HashMap<String, IDao> maps = new HashMap<String, IDao>();


	@RequestMapping("/call/{beanId}/{method}")
	public void callServer(@PathVariable("beanId") String beanId, @PathVariable("method") String metod, String args,
			String type, HttpServletResponse resp) throws IOException {
		JSONObject json = new JSONObject();
		try {
			Object object = ContextUtil.get(beanId);
			Method methodObj = ReflectionUtils.findMethod(object.getClass(), metod);
			if (methodObj == null) {
				json.put("code", "404");
				json.put("data", "method not fount");
				resp.getWriter().print(json.toJSONString());
				return;
			}

			Class<?>[] parameterTypes = methodObj.getParameterTypes();
			if (parameterTypes.length == 0) {
				json.put("code", "200");
				json.put("data", ReflectionUtils.invokeMethod(methodObj, object));
			} else {
				JSONArray params = JSONArray.parseArray(args);
				Object[] argObj = new Object[parameterTypes.length];
				for (int i = 0; i < argObj.length; i++) {
					Class<?> cls = parameterTypes[i];
					if(cls.isPrimitive()||cls==String.class){
						argObj[i] = params.getObject(i, cls);
					}
					JSONObject obj = params.getJSONObject(i);
					argObj[i] = JSONObject.toJavaObject(obj, parameterTypes[i]);
				}
				json.put("code", "200");
				json.put("data", ReflectionUtils.invokeMethod(methodObj, object, argObj));
			}
		} catch (Exception e) {
			json.put("code", "500");
			json.put("data", e.toString());
			log.error("fail to call server", e);
		}
		resp.setCharacterEncoding("utf8");
		resp.setContentType(type == null ? "text/html" : type);
		if (resp.getContentType().contains("text/html")) {
			resp.getWriter().print(json.get("data"));
		} else {
			resp.getWriter().print(json);
		}
		resp.getWriter().flush();
	}

	@ResponseBody
	@RequestMapping("/del")
	public JSONObject doDel(String namespace, long id) {
		IDao dao = getDaoObj(namespace);
		int delete = dao.delete(namespace, id);
		JSONObject json = new JSONObject();
		json.put("ok", delete > 0);
		json.put("id", id);
		return json;
	}

	@ResponseBody
	@RequestMapping("/add")
	public JSONObject doAdd(String clsName, String params) throws Exception {
		JSONObject json = JSONObject.parseObject(params);
		Class<?> cls = Class.forName(clsName);
		Object obj = JSON.toJavaObject(json, cls);
		IDao dao = getDaoObj(clsName);
		Object save = dao.save(cls.getSimpleName(), obj);
		JSONObject json2 = (JSONObject) JSONObject.toJSON(save);
		return json2;
	}

	@ResponseBody
	@RequestMapping("/query")
	public JSONObject jsTableQuery(String params) {
		JSONObject args = JSONObject.parseObject(params);
		String namespace = args.getString("namespace");
		int draw = args.getIntValue("draw");
		List<Object> datas = getDaoObj(namespace).getListByMap(namespace, args);
		args.put("recordsFiltered", datas.size());
		args.put("recordsTotal", datas.size());
		args.put("data", datas);
		args.put("draw", draw);
		return args;
	}

	private IDao getDaoObj(String namespace) {
		IDao dao = maps.get(namespace);
		return dao = dao == null ? daoTemplate : dao;
	}

	@Override
	public void onApplicationEvent(ContextRefreshedEvent arg0) {
		ApplicationContext ctx = arg0.getApplicationContext();
		Map<String, IDao> beans = ctx.getBeansOfType(IDao.class);
		for (Entry<String, IDao> item : beans.entrySet()) {
			IDao value = item.getValue();
			String processClassNames = value.processClassName();
			if (processClassNames == null) {
				log.info("DaoItf.processClassName is null:{}", value);
			} else {
				for (String cls : processClassNames.split(",")) {
					maps.put(cls, value);
				}
			}

		}
	}

}
